// https://www.lintcode.com/problem/topological-sorting/

/**
 * Definition for Directed graph.
 * class DirectedGraphNode {
 *     int label;
 *     ArrayList<DirectedGraphNode> neighbors;
 *     DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
 * };
 */

public class Solution {
    /*
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        // write your code here
        ArrayList<DirectedGraphNode> ret = new ArrayList<>();
        Map<DirectedGraphNode, Integer> map = new HashMap<>();
        Stack<DirectedGraphNode> stack = new Stack<>();
        for (DirectedGraphNode node : graph) {
            for (DirectedGraphNode neighbor : node.neighbors) {
                if (!map.containsKey(neighbor)) {
                    map.put(neighbor, 0);
                }
                map.put(neighbor, map.get(neighbor) + 1);
            }
        }
        for (DirectedGraphNode node : graph) {
            if (!map.containsKey(node)) {
                stack.push(node);
            }
        }
        while (!stack.empty()) {
            DirectedGraphNode node = stack.pop();
            ret.add(node);
            for (DirectedGraphNode neighbor : node.neighbors) {
                map.put(neighbor, map.get(neighbor) - 1);
                if (map.get(neighbor) == 0) {
                    stack.push(neighbor);
                }
            }
        }
        return ret;
    }
}